package jfprincesstests.elenaofsavoia;

import java.util.Arrays;

import puntaelena.facilitylocation.hillclimbing.solver.PEHillClimbingAlgorithmBuilder;
import static puntaelena.facilitylocation.hillclimbing.solver.agents.FcltCityNegotiateComputator.*;
import puntaelena.facilitylocation.hillclimbing.solver.agents.*;
import puntaelena.facilitylocation.hillclimbing.solver.services.DefaultFcltLocDataService;
import puntaelena.facilitylocation.hillclimbing.solver.services.ICoalitionsRegistry;
import puntaelena.facilitylocation.hillclimbing.solver.services.IFcltLocDataService;
import puntaelena.facilitylocation.hillclimbing.solver.services.IHillClimbingAgentRegistry;
import puntaelena.graphsupport.solver.IFacilityLocationSolver;
import puntaelena.graphsupport.IGraphGenerator;
import puntaelena.graphsupport.FacilitiesGraph;
import puntaelena.graphsupport.GenerateGrSettings;
import puntaelena.graphsupport.GraphSupportFront;

import laboratoryQ.junit.ignore.patch.BaseTestCase;
import laboratoryQ.computation.BaseUtils;
import jfuzzyprincepless.algorithm.structure.INegotiationConstruction;
import jfuzzyprincepless.algorithm.structure.ElementsAsAgentsNegotiationFor;
import jfuzzyprincepless.algorithm.structure.services.IWhileService;
import jfuzzyprincepless.negotiation.DefaultNegotiation;
import jfuzzyprincepless.negotiation.INegotiationContext;
import jfuzzyprincepless.negotiation.NegotiationUtils;
import jfuzzyprincepless.negotiation.services.IAgentsListService;
import jfuzzyprincepless.negotiation.services.impl.AgentsListService;
import jfuzzyprincepless.agents.BaseNegotiationAgent;
import jfuzzyprincepless.agents.INegotiatingAgent;

public class TestHillClimbingSolver extends BaseTestCase {
	public void testHillClimbingSolver() {
		IGraphGenerator generator = GraphSupportFront.expensiveCheapGenerator();
		int citiesCount = 150;
		int facilitiesCount = 60;
		GenerateGrSettings settings =
			new GenerateGrSettings(citiesCount, facilitiesCount);
		settings.neighborCountBeg = 10;
		settings.neighborCountRange = 5;
		settings.cheapEdgeBeg = 100;
		settings.cheapEdgeRange = 50;
		settings.expensiveEdgeBeg = 200;
		settings.expensiveEdgeRange = 100;
		settings.facilityPriceBeg = 200;
		settings.facilityPriceRange = 200;
		settings.triangleIneqEnabled = true;

		IFacilityLocationSolver f3Solver = GraphSupportFront.getFactor3Solver();

		PEHillClimbingAlgorithmBuilder builder = new PEHillClimbingAlgorithmBuilder();
		builder.addForAllCitiesRelinkTheBest();
		builder.addForChpUsflClsdFcltOpenRelikn();
		IFacilityLocationSolver hcSolver = builder.build();

		builder.addForFacilitySearchesAndClosesEnemies();
		IFacilityLocationSolver hcFcltAgainstSolver = builder.build(); 

		builder = new PEHillClimbingAlgorithmBuilder();
		builder.addForAllCitiesRelinkTheBest();
		builder.addForFacilitySearchesAndClosesEnemies();
		builder.addForChpUsflClsdFcltOpenRelikn();
		IFacilityLocationSolver hcFcltAgainstRevertOrderSolver = builder.build();

		builder = new PEHillClimbingAlgorithmBuilder();
		builder.addForAllCitiesRelinkTheBest();
		builder.addForChpUsflClsdFcltOpenRelikn();
		builder.addForFacilitySearchesAndClosesEnemies();
		builder.addWhileClosedFacilitiesCoalitions();
		IFacilityLocationSolver hcFcltCoalitionsSolver = builder.build();

		FacilitiesGraph fgraph = (FacilitiesGraph)generator.generate(settings);

		boolean[] isFcltOpenA = new boolean[facilitiesCount];
		int[] witnessesA = new int[citiesCount];
		f3Solver.solve(fgraph, isFcltOpenA, witnessesA);
		double priceA = GraphSupportFront
			.computeFacilityLocationCost(fgraph, isFcltOpenA, witnessesA);
		assertTrue(priceA < fgraph.getInfEdgeValue());
		int openFacilitiesCountA = getOpenFacilitiesCount(isFcltOpenA);
		assertTrue(openFacilitiesCountA < facilitiesCount);

		boolean[] isFcltOpenB = new boolean[facilitiesCount];
		int[] witnessesB = new int[citiesCount];
		hcSolver.solve(fgraph, isFcltOpenB, witnessesB);
		double priceB = GraphSupportFront
			.computeFacilityLocationCost(fgraph, isFcltOpenB, witnessesB);
		assertTrue(priceB < fgraph.getInfEdgeValue());
		int openFacilitiesCountB = getOpenFacilitiesCount(isFcltOpenB);
		assertTrue(openFacilitiesCountB < facilitiesCount);

		assertTrue(priceB <= priceA);
		assertTrue(priceA - priceB > 18110.0);
		// [ ] 47254.9221157188 - 29141.58191521015 = 18113.34020050865
		// old:
		// [2] 57859.6384058886 - 33160.50643829723 = 24699.131967591376
		// [1] 22694.733419352644 - 20024.033734154025 = 2670.6996851986187
		// [0] 22694.733419352644 - 22103.57079683537 = 591.1626225172731

		boolean[] isFcltOpenC = new boolean[facilitiesCount];
		int[] witnessesC = new int[citiesCount];
		hcFcltAgainstSolver.solve(fgraph, isFcltOpenC, witnessesC);
		double priceC = GraphSupportFront
			.computeFacilityLocationCost(fgraph, isFcltOpenC, witnessesC);
		assertTrue(priceC < fgraph.getInfEdgeValue());
		int openFacilitiesCountC = getOpenFacilitiesCount(isFcltOpenC);
		assertTrue(openFacilitiesCountC < facilitiesCount);

		assertTrue(priceC <= priceB);
		assertTrue(priceB - priceC > 415.0);
		// [ ] 29141.58191521015 - 28725.219450751723 = 416.362464458427
		// old:
		// [1] 33160.50643829723 - 32600.75227404152 = 559.754164255708
		// [0] 20024.033734154025 - 19965.062045613427 = 58.971688540597825

		boolean[] isFcltOpenCr = new boolean[facilitiesCount];
		int[] witnessesCr = new int[citiesCount];
		hcFcltAgainstRevertOrderSolver.solve(fgraph, isFcltOpenCr, witnessesCr);
		double priceCr = GraphSupportFront
			.computeFacilityLocationCost(fgraph, isFcltOpenCr, witnessesCr);
		assertTrue(priceCr < fgraph.getInfEdgeValue());
		int openFacilitiesCountCr = getOpenFacilitiesCount(isFcltOpenCr);
		assertTrue(openFacilitiesCountCr < facilitiesCount);

		assertTrue(priceCr <= priceA);
		assertTrue(priceB - priceCr > 210);
		// [ ]29141.58191521015 - 28927.045591970982 = 214.53632323916827
		// old
		// [0]20024.033734154025 - 19901.881672818 = 122.15206133602624
		/**
		 * NOTE: 19965.062045613427 <-> 19901.881672818 -- by random
		 */

		boolean[] isFcltOpenD = new boolean[facilitiesCount];
		int[] witnessesD = new int[citiesCount];
		hcFcltCoalitionsSolver.solve(fgraph, isFcltOpenD, witnessesD);
		double priceD = GraphSupportFront
			.computeFacilityLocationCost(fgraph, isFcltOpenD, witnessesD);
		assertTrue(priceD < fgraph.getInfEdgeValue());
		int openFacilitiesCountD = getOpenFacilitiesCount(isFcltOpenD);
		assertTrue(openFacilitiesCountD < facilitiesCount);

		assertTrue(priceD <= priceC);
		assertTrue(priceC - priceD > 805);
		// [ ] 28725.219450751723 - 27916.277265206485 = 808.9421855452383
		// old
		// [4] 28725.219450751723 - 28085.120674753776 = 640.0987759979471
		// [3] 32600.75227404152 - 31814.506490462463 = 786.2457835790556 mini improve 8-)
		// [2] 32600.75227404152 - 31821.28729153664 = 779.46498250488
		// [1] 32600.75227404152 - 32114.03420039271 = 486.71807364880806
		// [0] 32600.75227404152 - 31875.534530404075 = 725.2177436374441

		hcSolver.solve(fgraph, isFcltOpenB, witnessesB);
		double priceFIN = GraphSupportFront
			.computeFacilityLocationCost(fgraph, isFcltOpenB, witnessesB);
		assertEquals(priceB, priceFIN);
		
		BaseUtils.dispose(generator, f3Solver, hcSolver);
	}

	private int getOpenFacilitiesCount(boolean[] isFcltOpenA) {
		int n = isFcltOpenA.length;
		int result = 0;
		for (int i = 0; i < n; i++) {
			if (isFcltOpenA[i]) {
				result++;
			}
		}
		return result;
	}

	public void testIFcltLocDataService() {
		IGraphGenerator generator = GraphSupportFront.expensiveCheapGenerator();
		FacilitiesGraph fgraph = (FacilitiesGraph)generator
			.generate(new GenerateGrSettings(100));
		boolean[] isfcltOpen = new boolean[1];
		int[] witnesses = new int[1];

		INegotiationContext context =
			createHillClimbingNegotiationContext();
		IFcltLocDataService flServ = context.getService(IFcltLocDataService.class);
		INegotiationContext icontext = context;
		assertNotNull(icontext);
		flServ.setFacilityLocationData(fgraph, isfcltOpen, witnesses);

		assertSame(fgraph, flServ.getFgraph());
		assertSame(isfcltOpen, flServ.getFcltOpen());
		assertSame(witnesses, flServ.getWitnesses());
	}
	
	public void testFacilityCouldBePayedCondition() {
		PEHillClimbingAlgorithmBuilder builder =
			new PEHillClimbingAlgorithmBuilder();
		builder.addForAllCitiesRelinkTheBest();
		builder.addForChpUsflClsdFcltOpenRelikn();
		INegotiationConstruction
			facilityCouldBePayedConstruction =
				builder.buildConstruction();
		assertNotNull(facilityCouldBePayedConstruction);
		assertEquals(
			2,
			facilityCouldBePayedConstruction
				.getAgentsList().size()
		);
		
		INegotiationContext context =
			createHillClimbingNegotiationContext();
		int citiesCount = 10;
		int facilitiesCount = 3;
		FacilitiesGraph fgraph =
			new FacilitiesGraph(citiesCount, facilitiesCount);
		for (int i = 0; i < citiesCount; i++) {
			for (int j = 0; j < facilitiesCount; j++) {
				fgraph.setFSEdge(i, j, 100);
			}
		}
		for (int j = 0; j < facilitiesCount; j++) {
			fgraph.getFacilitiesPrices()[j] = 100;
		}
		fgraph.setFSEdge(5, 1, 65);
		fgraph.setFSEdge(6, 1, 65);
		fgraph.setFSEdge(7, 1, 65);
		boolean[] isFcltOpen = new boolean[facilitiesCount];
		int[] witnesses = new int[citiesCount];
		isFcltOpen[0] = true;
		Arrays.fill(witnesses, 0);
		double priceA = GraphSupportFront
			.computeFacilityLocationCost(
				fgraph,
				isFcltOpen,
				witnesses
			);
		initHillClimbingServices(context, fgraph, isFcltOpen, witnesses);
		context.registerService(facilityCouldBePayedConstruction);
		NegotiationUtils.defaultNegotiationIteration(context);

		assertEquals(
			citiesCount + facilitiesCount,
			context.getService(IAgentsListService.class).getAgentsList().size()
		);
		assertEquals(true, isFcltOpen[1]);
		assertEquals(1, witnesses[5]);
		assertEquals(1, witnesses[6]);
		assertEquals(1, witnesses[7]);
		double priveB = GraphSupportFront
			.computeFacilityLocationCost(fgraph, isFcltOpen, witnesses);
		assertTrue(priceA > priveB);
	}

	public void testComputeBestLinkProfit() {
		FacilitiesGraph fgraph = new FacilitiesGraph(10, 10);
		fgraph.setFSEdge(0, 0, 12);
		fgraph.setFSEdge(0, 1, 34);
		fgraph.setFSEdge(0, 2, 89);
		int[] witnesses = new int[fgraph.getCitiesCount()];
		Arrays.fill(witnesses, -1);
		boolean[] isFcltOpen = new boolean[fgraph.getFacilitiesCount()];
		isFcltOpen[1] = true;

		witnesses[0] = 1;
		assertEquals(
			0.0,
			computeBestWitnessProfit(
				fgraph,
				witnesses,
				isFcltOpen,
				0
			)
		);

		isFcltOpen[2] = true;
		assertEquals(
			0.0,
			computeBestWitnessProfit(
				fgraph,
				witnesses,
				isFcltOpen,
				0
			)
		);

		isFcltOpen[0] = true;
		assertEquals(
			34.0 - 12.0,
			computeBestWitnessProfit(
				fgraph,
				witnesses,
				isFcltOpen,
				0
			)
		);

		fgraph.setFSEdge(0, 2, 10);
		assertEquals(
			34.0 - 10.0,
			computeBestWitnessProfit(
				fgraph,
				witnesses,
				isFcltOpen,
				0
			)
		);
	}

	public void testComputeRedistributeFacilityProfit() {
		FacilitiesGraph fgraph = new FacilitiesGraph(10, 10);
		fgraph.setFSEdge(0, 1, 12);
		fgraph.setFSEdge(1, 1, 23);
		fgraph.setFSEdge(2, 1, 34);

		fgraph.setFSEdge(0, 2, 98);
		fgraph.setFSEdge(1, 2, 11);
		fgraph.setFSEdge(2, 2, 23);

		fgraph.setFSEdge(0, 3, 50);

		boolean[] isFcltOpen = new boolean[fgraph.getFacilitiesCount()];

		int[] witnesses = new int[fgraph.getCitiesCount()];
		Arrays.fill(witnesses, 9);
		isFcltOpen[9] = true;
		witnesses[0] = 1;
		witnesses[1] = 1;
		witnesses[2] = 1;
		isFcltOpen[1] = true;

		assertEquals(
			-fgraph.getInfEdgeValue(),
			computeRedistributeFacilityProfit(
				fgraph,
				witnesses,
				isFcltOpen,
				1
			)
		);

		isFcltOpen[2] = true;
		assertEquals(
			12.0 + 23.0 + 34.0 - 98.0 - 11.0 - 23.0,
			computeRedistributeFacilityProfit(
				fgraph,
				witnesses,
				isFcltOpen,
				1
			)
		);

		isFcltOpen[3] = true;
		assertEquals(
			12.0 + 23.0 + 34.0 - 50.0 - 11.0 - 23.0,
			computeRedistributeFacilityProfit(
				fgraph,
				witnesses,
				isFcltOpen,
				1
			)
		);
	}
	
	public void testNormRate() {
		double[] rate = new double [] { 1, 2, 1, 1, 1 };
		normRate(rate, 1e30, 1e-5);
		for (int i = 0; i < rate.length; i++) {
			if (i != 1) {
				assertTrue(rate[i] < rate[1]);
			}
		}
		
		rate = new double [] { 1, 2, 1, 3, 1 };
		normRate(rate, 1e30, 1e-5);
		for (int i = 0; i < rate.length; i++) {
			if (i != 1 && i != 3) {
				assertTrue(rate[i] < rate[1]);
				assertTrue(rate[i] < rate[3]);
			}
		}
		assertTrue(rate[1] < rate[3]);
		
		rate = new double []
			{ 1, 21, 1, 31, -new FacilitiesGraph(1, 1).getInfEdgeValue() };
		double[] rate1 = new double [] { 1, 21, 1, 31, -19 };
		normRate(rate, 1e30, 1e-5);
		normRate(rate1, 1e30, 1e-5);
		for (int i = 0; i < rate.length; i++) {
			assertTrue(Math.abs(rate1[i] - rate[i]) < 1e-5);
		}
	}

	public void testCompareRates() {
		double[] first    = new double[] {  1,  1, 10,  1,  1, 10,  1,  1,  1,  1,  1, 10,  1,  1 };
		double[] secondA  = new double[] {  1,  1,  3,  1,  1,  3,  1,  1,  1,  1,  1,  3,  1,  1 };
		double[] secondB  = new double[] {  1,  1,  7,  1,  1,  7,  1,  1,  1,  1,  1,  3,  1,  1 };
		double[] big      = new double[] {  1,  1,100,  1,  1,100,  1,  1,  1,  1,  1,100,  1,  2 };
		double[] single   = new double[] {  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1 };
		double[] absdiff  = new double[] {  1,  1,  1, 10,  1,  1,  1,  1,  1,  1,  1,  1,  10,  1 };

		normRate(first, 1e30, 1e-5);
		normRate(secondA, 1e30, 1e-5);
		normRate(secondB, 1e30, 1e-5);
		normRate(big, 1e30, 1e-5);
		normRate(single, 1e30, 1e-5);
		normRate(absdiff, 1e30, 1e-5);

		double eps = 1e-5;

		// single
		assertTrue(
			computeRateSimilarity(first, single) <
			computeRateSimilarity(first, secondA) - eps
		);
		assertTrue(
			computeRateSimilarity(first, single) <
			computeRateSimilarity(first, secondB) - eps
		);
		assertTrue(
			computeRateSimilarity(first, single) <
			computeRateSimilarity(first, big) - eps
		);
		assertTrue(
			computeRateSimilarity(first, absdiff) <
			computeRateSimilarity(first, single) - eps
		);

		// first second big
		assertTrue(
			computeRateSimilarity(first, secondB) <
			computeRateSimilarity(first, secondA) - eps
		);
		assertTrue(
			computeRateSimilarity(first, big) <
			computeRateSimilarity(first, secondA) - eps
		);
	}
	
	public void testFacilityCoalition() {
		FacilitiesGraph fgraph = new FacilitiesGraph(30, 20);
		IFcltLocDataService flServ = new DefaultFcltLocDataService();
		flServ.setFacilityLocationData(
			fgraph,
			new boolean[fgraph.getFacilitiesCount()],
			null
		);
//		ICoalitionsRegistry registry =
//			CoalitionsRegistry
//				.createFromDataWithSeparatedFLServ(fgraph);
		CollaboratingFacilityAgent agent = new CollaboratingFacilityAgent(12);
		
		FacilityCoalition coalition = agent.getCoalition(flServ);
		assertNotNull(coalition);
		assertSame(coalition, agent.getCoalition(flServ));

		double[] enemyRate = coalition.getEnemyRate();
		assertEquals(fgraph.getFacilitiesCount(), enemyRate.length);
		assertSame(enemyRate, coalition.getEnemyRate());
	}

//	public void testComputeOpenCoalitionProfit() {
//		int citiesCount = 10;
//		int facilitiesCount = 10;
//		FacilitiesGraph fgraph = new FacilitiesGraph(citiesCount, facilitiesCount);
//		int[] witnesses = new int[citiesCount];
//		Arrays.fill(witnesses, -1);
//		boolean[] isFcltOpen = new boolean[facilitiesCount];
//
//		isFcltOpen[0] = true;
//		Arrays.fill(witnesses, 0);
//		for (int i = 0; i < citiesCount; i++) {
//			fgraph.setFSEdge(i, 0, 100);
//		}
//		Arrays.fill(fgraph.getFacilitiesPrices(), 200);
//
//		FacilityCoalition coalitionA =
//			new FacilityCoalition(new CollaboratingFacilityAgent(1));
//
//		assertEquals(
//			-fgraph.getInfEdgeValue(),
//			computeOpenCoalitionProfit(fgraph, coalitionA)
//		);
//	}

	public void testCoalitionApplyWithSingleFacility() {
		/**
		 * cities 5, 6 & facilities 3, 4 are fake, c5 -> f3, c6 -> f4
		 */
		FacilitiesGraph fgraph = new FacilitiesGraph(7, 5);
		for (int i = 0; i < fgraph.getCitiesCount(); i++) {
			fgraph.setFSEdge(i, 1, 100.0);
			fgraph.setFSEdge(i, 0, 110.0);
		}
		fgraph.setFSEdge(4, 2, 90.0);
		fgraph.setFSEdge(4, 1, 110.1);
		fgraph.setFSEdge(4, 0, 110.0);
		fgraph.setFSEdge(5, 3, 10.0);
		fgraph.setFSEdge(6, 4, 10.0);
		Arrays.fill(fgraph.getFacilitiesPrices(), 150);
		fgraph.getFacilitiesPrices()[0] = 100;

		boolean[] isFcltOpen =
			new boolean[fgraph.getFacilitiesCount()];
		isFcltOpen[1] = true;
		isFcltOpen[2] = true;
		isFcltOpen[3] = true;
		isFcltOpen[4] = true;
		int[] witnesses = new int[fgraph.getCitiesCount()];
		Arrays.fill(witnesses, 1);
		witnesses[4] = 2;
		witnesses[5] = 3;
		witnesses[6] = 4;


		INegotiationContext context =
			createHillClimbingNegotiationContext();
		initHillClimbingServices(
			context,
			fgraph,
			isFcltOpen,
			witnesses
		);
		IFcltLocDataService flServ =
			context.getService(IFcltLocDataService.class);
		flServ.setFacilityLocationData(fgraph, isFcltOpen, witnesses);
		context.registerService(new CoalitionsRegistry());
		context.registerService(new AgentsListService());

		new ElementsAsAgentsNegotiationFor(
			new IntroduceCitiesContext2forAgents()
		).onNegotiationStart(context);
		new ElementsAsAgentsNegotiationFor(
			new IntroduceClosedFacilitiesMakeCoalitionsContext2forAgents()
		).onNegotiationStart(context);

		CollaboratingFacilityAgent agent = context
			.getService(IHillClimbingAgentRegistry.class)
			.getCollFcltAgent(0);
		assertNotNull(agent);

		assertEquals(2, witnesses[4]);
		agent.negotiate(context);
		assertEquals(0, witnesses[4]);
	}
	
	public void testCoalitionJoinAndApply() {
		/**
		 * coalition: { 0, 1 } against { 2, 3 } with cities { 0, 1; 2, 3 }
		 * collect all: 4 / 200 / with best-client cities { 4, 5, 6 } 
		 * 7, 8 -> 5 and 9, 10 -> 6 are extra connections / 100 /
		 */
		FacilitiesGraph fgraph = new FacilitiesGraph(11, 7);
		for (int i = 0; i < fgraph.getCitiesCount(); i++) {
			fgraph.setFSEdge(i, 4, 250.0);
		}
		fgraph.setFSEdge(0, 2, 100.0);
		fgraph.setFSEdge(1, 2, 100.0);
		fgraph.setFSEdge(0, 0, 120.0);
		fgraph.setFSEdge(1, 1, 120.0);
		
		fgraph.setFSEdge(2, 3, 100.0);
		fgraph.setFSEdge(3, 3, 100.0);
		fgraph.setFSEdge(2, 0, 130.0);
		fgraph.setFSEdge(3, 1, 130.0);
		
		fgraph.setFSEdge(7, 5, 100.0);
		fgraph.setFSEdge(8, 5, 100.0);
		fgraph.setFSEdge(9, 6, 100.0);
		fgraph.setFSEdge(10, 6, 100.0);
		Arrays.fill(fgraph.getFacilitiesPrices(), 200);
		fgraph.getFacilitiesPrices()[0] -= 50;
		fgraph.getFacilitiesPrices()[1] -= 70;
		
		boolean[] isFcltOpen =
			new boolean[fgraph.getFacilitiesCount()];
		isFcltOpen[2] = true;
		isFcltOpen[3] = true;
		isFcltOpen[4] = true;
		isFcltOpen[5] = true;
		isFcltOpen[6] = true;
		int[] witnesses = new int[fgraph.getCitiesCount()];
		Arrays.fill(witnesses, 4);
		witnesses[0] = 2;
		witnesses[1] = 2;
		witnesses[2] = 3;
		witnesses[3] = 3;
		witnesses[7] = 5;
		witnesses[8] = 5;
		witnesses[9] = 6;
		witnesses[10] = 6;
		
		INegotiationContext context =
			createHillClimbingNegotiationContext();
		initHillClimbingServices(
			context,
			fgraph,
			isFcltOpen,
			witnesses
		);
		context.registerService(new AgentsListService());

		new ElementsAsAgentsNegotiationFor(
			new IntroduceCitiesContext2forAgents()
		).onNegotiationStart(context);
		
		assertNull(context.getService(IWhileService.class));
		new ElementsAsAgentsNegotiationFor(
			new IntroduceClosedFacilitiesMakeCoalitionsContext2forAgents()
		).onNegotiationStart(context);
		CoalitionsRegistry registry = (CoalitionsRegistry)
			context.getService(ICoalitionsRegistry.class);
		assertNotNull(context.getService(IWhileService.class));
		assertSame(
			registry,
			context.getService(IWhileService.class)
		);

		IHillClimbingAgentRegistry hcagReg =
			context.getService(IHillClimbingAgentRegistry.class);
		CollaboratingFacilityAgent agent0 = hcagReg.getCollFcltAgent(0);
		CollaboratingFacilityAgent agent1 = hcagReg.getCollFcltAgent(1);

		boolean alive;

		assertEquals(2, witnesses[0]);
		assertEquals(2, witnesses[1]);
		assertEquals(3, witnesses[2]);
		assertEquals(3, witnesses[3]);

		alive = agent0.negotiate(context);
		assertTrue(alive);
		alive = agent1.negotiate(context);
		assertTrue(alive);

		registry.negotiate(context);

		alive = agent0.negotiate(context);
		assertTrue(alive);
		alive = agent1.negotiate(context);
		assertTrue(alive);

		assertEquals(0, witnesses[0]);
		assertEquals(1, witnesses[1]);
		assertEquals(0, witnesses[2]);
		assertEquals(1, witnesses[3]);

		// ### ### ### ### ### ### ### ### ### 
		final int[] counter_ptr = new int[] { 0 };
		BaseNegotiationAgent counter = new BaseNegotiationAgent() {
			@Override
			public boolean negotiate(INegotiationContext context) {
				counter_ptr[0]++;
				assertTrue(counter_ptr[0] < 200);
				return context.getService(IWhileService.class)
					.isAgentAlive(this);
			}
		};
		context.getService(IAgentsListService.class)
			.getAgentsList().addAll(
				Arrays.asList(
					agent0,
					agent1,
					registry,
					counter
				)
			);
		new DefaultNegotiation().negotiate(context);
		assertEquals(2, counter_ptr[0]); // 1 -- may be broken
	}
	
	public void testExcludeOpenFacilitiesFromCoalitions() {
		FacilitiesGraph fgraph = new FacilitiesGraph(20, 10);
		boolean[] isFcltOpen = new boolean[fgraph.getFacilitiesCount()];
		int[] witnesses = new int[fgraph.getCitiesCount()];
		isFcltOpen[0] = true;

		INegotiationContext context =
			createHillClimbingNegotiationContext();


		IHillClimbingAgentRegistry hcagReg =
			context.getService(IHillClimbingAgentRegistry.class);
		IFcltLocDataService flServ =
			context.getService(IFcltLocDataService.class);
		hcagReg.init(fgraph);
		CollaboratingFacilityAgent agA = new CollaboratingFacilityAgent(0);
		hcagReg.addCollFcltAgent(agA);
		CollaboratingFacilityAgent agB = new CollaboratingFacilityAgent(1);
		hcagReg.addCollFcltAgent(agB);
		CollaboratingFacilityAgent agC = new CollaboratingFacilityAgent(2);
		hcagReg.addCollFcltAgent(agC);
		flServ.setFacilityLocationData(fgraph, isFcltOpen, witnesses);

		CoalitionsRegistry coalReg =
			CoalitionsRegistry
				.createFromDataWithSeparatedFLServ(
					fgraph,
					isFcltOpen,
					witnesses
				);
		FacilityCoalition coalB = agB.getCoalition(flServ);
		coalB.getMembers().add(agA);
		coalB.getMembers().add(agC);
		
		context.registerService(
			new AgentsListService(
				Arrays.<INegotiatingAgent>asList(agA, agB, agC, coalReg)
			)
		);
		context.registerService(coalReg);
		
		flServ.setFacilityLocationData(fgraph, isFcltOpen, witnesses);
		context.registerService(flServ);

		assertEquals(3, coalB.getMembers().size());
		assertEquals(
			"coalition: [ColAg: 1, ColAg: 0, ColAg: 2]",
			coalB.toString()
		);
		agB.negotiate(context);
		assertEquals(2, coalB.getMembers().size());
		assertEquals(
			"coalition: [ColAg: 1, ColAg: 2]",
			coalB.toString()
		);
	}
}